package javavis.jip3d.gui.dataobjects;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;

import javavis.base.JIPException;
import javavis.base.JIPToolkit;
import javavis.jip2d.base.bitmaps.JIPBmpByte;
import javavis.jip3d.geom.MyTransform;
import javavis.jip3d.geom.Point3D;
import javavis.jip3d.geom.PointSR4K;
import javavis.jip3d.gui.ScreenData;
import javavis.jip3d.gui.ScreenOptions;

import javax.media.j3d.PointArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3b;
import javax.vecmath.Point3f;
/**
 * SR4000Set3D Class.
 * Allows working with SR4000 camera data.
 * @author mcazorla
 *
 */
public class SR4000Set3D extends ScreenData {
	private static final long serialVersionUID = 8539653941133443621L;
	
	private static final int nColumns=176;
	private static final int nRows=144;
	
	/**
	 * @uml.property  name="amplitude"
	 * @uml.associationEnd  
	 */
	private JIPBmpByte amplitude;

	/**
	 * @uml.property  name="confidenceMap"
	 * @uml.associationEnd  
	 */
	private JIPBmpByte confidenceMap;

	/**
	 * @uml.property  name="distances"
	 * @uml.associationEnd  
	 */
	private JIPBmpByte distances;
	/**
	 * @uml.property  name="timeStamp"
	 */
	private long timeStamp;

	public SR4000Set3D(ScreenOptions opt) {
		super(opt);
		opt.global_color = false;
		opt.improved = false;
		this.setType(ScreenOptions.tSR4000SET3D);
	}

	@Override
	protected TransformGroup paint() {
		TransformGroup tgRet=new TransformGroup();
		int tam, cont;
		Object []elements = data.elements();
		Point3f []points;
		tam = elements.length;
		points = new Point3f[tam];
		PointArray geometria;

		if(scr_opt.global_color)
		{
			geometria = new PointArray(tam,PointArray.COORDINATES);
		}
		else
		{
			geometria = new PointArray(tam,PointArray.COORDINATES|PointArray.COLOR_3);
		}

		for(cont=0;cont<tam;cont++)
		{
			points[cont] = new Point3f(((Point3D)elements[cont]).getCoordsf());
		}

		geometria.setCoordinates(0, points);
		if(!scr_opt.global_color)
		{
			for(cont=0;cont<tam;cont++)
				geometria.setColor(cont, ((Point3D)elements[cont]).color);
		}
		Shape3D forma = new Shape3D(geometria,object_app);
		forma.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
		tgRet.addChild(forma);

		return tgRet;
	}

	@Override
	public int readData(String file_name, String path) {
		Reader fr;
		StreamTokenizer st;
		PointSR4K point;
		int numPoints, cont;

		name = file_name;

		try
		{
			fr=new FileReader(path+file_name);
			st=new StreamTokenizer(fr);
			String comentario="#";
			byte []bcom=comentario.getBytes();
			int icom=(int)bcom[0];
			st.commentChar(icom);

			//Read number of points
			st.nextToken();
			numPoints=(int)st.nval;
			//Read timestamp
			st.nextToken();
			timeStamp = (long)st.nval;
			for (cont=0; cont<numPoints; cont++) {
				point = new PointSR4K(st);
				data.insert(point.getCoords(), point);
			}

			scr_opt.num_points = data.size();
		} catch (IOException e)
		{
			System.out.println("SR4000Set3D::readData Error: can not read data from "+path+file_name);
			return -1;
		}

		return data.size();
	}
	
	/**
	 * We maintain this method just for compatibility issues
	 * @deprecated
	 * @param file_name
	 * @param path
	 * @return
	 */
	public int readDataOld(String file_name, String path) {

		Reader fr;
		StreamTokenizer st;
		Point3D point;
		
		try {
			amplitude=new JIPBmpByte(nColumns, nRows);
			confidenceMap=new JIPBmpByte(nColumns, nRows);
			distances=new JIPBmpByte(nColumns, nRows);
		}
		catch(JIPException e) {System.out.println(e);}

		name = file_name;

		try
		{
			fr=new FileReader(path+file_name);
			st=new StreamTokenizer(fr);
			String comentario="%";
			byte []bcom=comentario.getBytes();
			int icom=(int)bcom[0];
			st.commentChar(icom);

			double []xData= new double[nColumns*nRows];
			double []yData= new double[nColumns*nRows];
			double []zData= new double[nColumns*nRows];
			double []val= new double[nColumns*nRows];
			double []conf= new double[nColumns*nRows];
			
			double maxDist=0.0;
			for (int i=0; i<nRows*nColumns; i++) {
					st.nextToken();
					zData[i]=-st.nval;
					if (st.nval>maxDist) maxDist=st.nval;
			}
			for (int i=0; i<nRows*nColumns; i++) {
					st.nextToken();
					xData[i]=-st.nval;
			}
			for (int i=0; i<nRows*nColumns; i++) {
					st.nextToken();
					yData[i]=st.nval;
			}
			

			double maxAmp=0.0;
			// Amplitude value: keep the max value
			for (int i=0; i<nRows*nColumns; i++) {
					st.nextToken();
						val[i]=st.nval;
						if (maxAmp<st.nval) maxAmp=st.nval;
				}
			double auxAmp=255.0/maxAmp;
			//Equalization of the amplitude
			int []histo=new int[256];
			for (int i=0; i<nRows*nColumns; i++) {
				val[i] *= auxAmp;
				histo[(int)(val[i])]++;
			}
			for (int i=0; i<254; i++) {
				histo[i+1]+=histo[i];
			}
			for (int i=0; i<nRows*nColumns; i++) {
				val[i]=255*(histo[(int)(val[i])]-1)/(nRows*nColumns-1);
			}

			
			double maxConf=0.0;
			// Confidence value
			for (int i=0; i<nRows*nColumns; i++) {
					st.nextToken();
					conf[i]=(int)st.nval;
					if (conf[i]>maxConf) maxConf=conf[i];
				}
			st.nextToken();
			timeStamp=(long)st.nval;

			double auxConf=255/maxConf;
			double auxDist=255.0/maxDist;
			
			//Save images
			try {
				for (int r=0; r<nRows; r++) 
					for (int c=0; c<nColumns; c++) {
						amplitude.setPixel(c, r, val[r*nColumns+c]);
						confidenceMap.setPixel(c, r, conf[r*nColumns+c]*auxConf);
						distances.setPixel(c, r, -zData[r*nColumns+c]*auxDist);
					}
			}
			catch(JIPException e) {System.out.println(e);}
			
			for (int r=0; r<nRows; r++) 
					for (int c=0; c<nColumns; c++) {
						int i=r*nColumns+c;
						if (conf[i]>0) {
							Color3b col=new Color3b((byte)(val[i]),(byte)(val[i]),(byte)(val[i]));
							point = new Point3D(xData[i], yData[i], zData[i], col, r, c);
							data.insert(point.getCoords(), point);
						}
					}
			try {
				JIPToolkit.saveImageIntoFile(amplitude, path+file_name+".amp.jip");
				JIPToolkit.saveImageIntoFile(confidenceMap, path+file_name+".conf.jip");
				JIPToolkit.saveImageIntoFile(distances, path+file_name+".dist.jip");
			} catch (JIPException e) {
				e.printStackTrace();
			}
			scr_opt.num_points = data.size();

		} catch (IOException e)
		{
			System.out.println("SR4000Set3D::readData Error: can not read data from "+path+file_name);
			return -1;
		}

		return data.size();
	}

	@Override
	public void writeData(String name, String path) {
		int cont;
		int num_puntos = data.size();
		Object []elements = data.elements();

		if(path.charAt(path.length()-1)!='/')
			path += '/';

		FileWriter fw;
		try
		{
			fw = new FileWriter(path+name);
			fw.write(num_puntos+" ");
			fw.write("\n");

			for(cont=0;cont<num_puntos;cont++)
			{
				fw.write(((Point3D)elements[cont]).toString());
				fw.write("\n");
			}
			fw.close();

		} catch(IOException e)
		{
			System.err.println("Error:" + e.getMessage());
		}

	}

	@Override
	public void applyTransform(MyTransform trans) {
		int tam, cont;
		Object []elements;
		Point3D element;
		elements = elements();
		tam = elements.length;

		for(cont=0;cont<tam;cont++)
		{
			element = (Point3D)elements[cont];
			element.applyTransform(trans);
		}
	}

	/**
	 * @return the ncolumns
	 */
	public static int getNcolumns() {
		return nColumns;
	}

	/**
	 * @return the nrows
	 */
	public static int getNrows() {
		return nRows;
	}

}
